﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace AutoSnake
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }

        private Graphics GRAPHICS_MAP;
        private Graphics GRAPHICS_SNACK;

        private List<Point> LIST_SNACK;
        private Dictionary<string, Point> DICT_MAP;

        private readonly int SNACK_WEIGHT = 10;
        private int SNACK_DIRECTION = 1;  // 0: 左; 1: 右; 2: 上; 3: 下
        private Point FOOD;

        private readonly Color COLOR_MAP = ColorTranslator.FromHtml("#DBDBDB");
        private readonly Color COLOR_SNACK_HEAD = ColorTranslator.FromHtml("#383838");
        private readonly Color COLOR_FOOD = ColorTranslator.FromHtml("#A83838");

        private Timer TIMER_SNACK;

        private Random RANDOM;

        private void FormMain_Load(object sender, EventArgs e)
        {
            RANDOM = new Random();

            GRAPHICS_MAP = pnlMap.CreateGraphics();
            GRAPHICS_SNACK = pnlMap.CreateGraphics();

            TIMER_SNACK = new Timer
            {
                Interval = 100
            };
            TIMER_SNACK.Tick += TIMER_SNACK_Tick;

            StartGame();

            TIMER_SNACK.Start();
        }

        private void pnlMap_Paint(object sender, PaintEventArgs e)
        {
            for (int i = 0; i < pnlMap.Height; i+= SNACK_WEIGHT + 1)
            {
                GRAPHICS_MAP.DrawLine(new Pen(COLOR_MAP), 0, i, pnlMap.Width, i);
            }
            for (int i = 0; i < pnlMap.Width; i += SNACK_WEIGHT + 1)
            {
                GRAPHICS_MAP.DrawLine(new Pen(COLOR_MAP), i, 0, i, pnlMap.Height);
            }
        }

        private void TIMER_SNACK_Tick(object sender, EventArgs e)
        {
            Point snackHead = LIST_SNACK.First(); // 蛇头
            Point snackTail = LIST_SNACK.Last();  // 蛇尾

            LIST_SNACK.Remove(snackTail);
            string dictKey = String.Format("{0}|{1}", snackTail.X, snackTail.Y);
            if (DICT_MAP.ContainsKey(dictKey)) { DICT_MAP.Remove(dictKey); }

            switch (SNACK_DIRECTION)
            {
                case 0:
                    snackHead.X -= 11;
                    if (snackHead.X + 11 <= 1) { snackHead.X = pnlMap.Width - 11; }
                    break;
                case 1:
                    snackHead.X += 11;
                    if (snackHead.X + 11 > pnlMap.Width) { snackHead.X = 1; }
                    break;
                case 2:
                    snackHead.Y -= 11;
                    if (snackHead.Y + 11 <= 1) { snackHead.Y = pnlMap.Height - 11; }
                    break;
                case 3:
                    snackHead.Y += 11;
                    if (snackHead.Y + 11 > pnlMap.Height) { snackHead.Y = 1; }
                    break;
            }

            // 判断游戏结束
            dictKey = String.Format("{0}|{1}", snackHead.X, snackHead.Y);
            if (DICT_MAP.ContainsKey(dictKey)) {
                FOOD = Point.Empty;
                StartGame();
            }

            // 判断是否吃到食物
            List<Point> listSnack = new List<Point>();
            if (snackHead == FOOD) {
                listSnack.Add(FOOD);
                FOOD = Point.Empty;
            }
            listSnack.Add(snackHead);
            snackHead = listSnack.First();

            foreach (Point item in LIST_SNACK)
            {
                listSnack.Add(item);

                dictKey = String.Format("{0}|{1}", item.X, item.Y);
                if (DICT_MAP.ContainsKey(dictKey) == false) { DICT_MAP.Add(dictKey, item); }
            }

            // 绘制画面
            GRAPHICS_SNACK.FillRectangle(new SolidBrush(pnlMap.BackColor), snackTail.X, snackTail.Y, SNACK_WEIGHT, SNACK_WEIGHT);
            GRAPHICS_SNACK.FillRectangle(new SolidBrush(COLOR_SNACK_HEAD), snackHead.X, snackHead.Y, SNACK_WEIGHT, SNACK_WEIGHT);

            // 投喂食物
            FeedFood();

            LIST_SNACK = listSnack;
        }

        private void FormMain_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyValue)
            {
                case 37: // 左
                    if (SNACK_DIRECTION != 1) { SNACK_DIRECTION = 0; }
                    break;
                case 38: // 上
                    if (SNACK_DIRECTION != 3) { SNACK_DIRECTION = 2; }
                    break;
                case 39: // 右
                    if (SNACK_DIRECTION != 0) { SNACK_DIRECTION = 1; }
                    break;
                case 40: // 下
                    if (SNACK_DIRECTION != 2) { SNACK_DIRECTION = 3; }
                    break;
            }
        }

        private void StartGame()
        {
            GRAPHICS_MAP.Clear(pnlMap.BackColor);
            pnlMap_Paint(null, null);

            LIST_SNACK = new List<Point>
            {
                new Point(24 + (24 - 1) * 10, 25 + (25 - 1) * 10),
                new Point(23 + (23 - 1) * 10, 25 + (25 - 1) * 10),
                new Point(22 + (22 - 1) * 10, 25 + (25 - 1) * 10),
                new Point(21 + (21 - 1) * 10, 25 + (25 - 1) * 10),
                new Point(20 + (20 - 1) * 10, 25 + (25 - 1) * 10)
            };

            DICT_MAP = new Dictionary<string, Point>();
        }

        private void FeedFood()
        {
            if (FOOD == Point.Empty) {
                List<Point> unusedPointList = new List<Point>();
                for (int rowIndex = 0; rowIndex < pnlMap.Height - SNACK_WEIGHT; rowIndex += SNACK_WEIGHT + 1)
                {
                    for (int colIndex = 0; colIndex < pnlMap.Width - SNACK_WEIGHT; colIndex += SNACK_WEIGHT + 1)
                    {
                        string dictKey = String.Format("{0}|{1}", rowIndex + 1, colIndex + 1);
                        if (DICT_MAP.ContainsKey(dictKey) == false)
                        {
                            unusedPointList.Add(new Point(rowIndex + 1, colIndex + 1));
                        }
                    }
                }

                if (unusedPointList.Count > 0)
                {
                    int randomPointIndex = RANDOM.Next(0, unusedPointList.Count - 1);
                    FOOD = unusedPointList[randomPointIndex];
                    GRAPHICS_SNACK.FillRectangle(new SolidBrush(COLOR_SNACK_HEAD), FOOD.X, FOOD.Y, SNACK_WEIGHT, SNACK_WEIGHT);
                }

                unusedPointList.Clear();
            }
        }
    }
}
